package sess

import (
	"context"
	"net"
	"src/gcommon"
	"src/zeus/iserver"
	"src/zeus/logger"
	"src/zeus/msgdef"
	"src/zeus/msghandler"
	"src/zeus/pool"
	"src/zeus/safecontainer"
	"src/zeus/serializer"
	"src/zeus/threads"
	"sync/atomic"
	"time"
)

const (
	isClientToSrvSessionTrue  = true  //我是客户端, 我要连接别的服务器,会话是与服务器通信的
	isSrvToClientSessionFalse = false //我是服务器端,收到的客户端会话,会话是与客户端通信的
)

func newSess(conn net.Conn, notifier IConnNotify, encryEnabled, isClientToSrv bool) iserver.ISess {
	sess := &NetSess{
		IMsgHandler: msghandler.NewMsgHandler(),
		callback:    notifier,
		conn:        conn,
		_isVerified: false,
		sendBuf:     safecontainer.NewSafeListT[any](),
		BuffData:    make([]byte, MaxMsgBuffer),

		id:               0,
		hbTimerInterval:  time.Duration(gcommon.GetCfgInst().Config.HBTimer) * time.Second,
		hbTickerInterval: time.Duration(gcommon.GetCfgInst().Config.HBTicker) * time.Second,
		// hbTimerInterval:  time.Duration(viper.GetInt("Config.HBTimer")) * time.Second,
		// hbTickerInterval: time.Duration(viper.GetInt("Config.HBTicker")) * time.Second,
		closeTimer: time.NewTimer(time.Hour),

		_encryEnabled:      encryEnabled,
		_isClientToSrvSess: isClientToSrv,
	}
	sess.closeTimer.Stop()

	return sess
}

// NetSess 代表一个网络连接
type NetSess struct {
	iserver.IMsgHandler
	//管理器
	callback IConnNotify
	//链接
	conn net.Conn
	//发送消息的队列
	sendBuf *safecontainer.SafeListT[any]
	//管理协程器
	thgo *threads.ThreadGo
	//关自己的协程
	calrecv, calsend context.CancelFunc
	/* 定时器 */
	closeTimer       *time.Timer   // 退出链接定时器
	hbTimer          *time.Timer   //超时主动断开连接
	hbTimerInterval  time.Duration //超时时间
	hbTicker         *time.Ticker  //心跳定时器（主动连接对方面的时候，会使用）
	hbTickerInterval time.Duration //心跳时间
	//表示连接的ID，一般与上层的服务器ID或是用户ID一致
	id uint64
	//如果连接是服务器过来的话，那就是服务器类型，0表示客户端连接
	stype iserver.ServerType
	//是否加密
	_encryEnabled bool
	//是否自己是客户端发起的会话, true 表示会话是跟服务器通信的. false 表示会话是跟客户端通信的.
	_isClientToSrvSess bool
	//是否验证过
	_isVerified bool
	//是否关闭了
	_isClosed atomic.Bool
	// 是否需要打印
	_isInputMsg atomic.Bool
	_isRecvMsg  atomic.Bool

	// sendRawBuf  *safecontainer.SafeList
	// lastMsg    msgdef.IMsg
	// lastRawMsg []byte
	//用来收消息的
	BuffData []byte
}

// SetMsgHandler 设置消息处理器
func (sess *NetSess) SetMsgHandler(handler iserver.IMsgHandler) {
	if handler == sess || handler == nil {
		sess.IMsgHandler = msghandler.NewMsgHandler()
	} else {
		sess.IMsgHandler = handler
	}
}

// Start 验证完成
func (this *NetSess) Start(thgo *threads.ThreadGo) {
	if thgo == nil {
		this.thgo = threads.NewThreadGo()
	} else {
		this.thgo = thgo
	}
	if this._isClientToSrvSess {
		this.hbTicker = time.NewTicker(this.hbTickerInterval) //客户端对服务器的会话，发起心跳的 定时器
		// defer this.hbTicker.Stop()
		this.hbTimer = &time.Timer{}
	} else if this.IsSrvToClientSess() {
		this.hbTicker = &time.Ticker{}
		this.hbTimer = time.NewTimer(this.hbTimerInterval) //服务端对客户端的会话，定时器只用来超时断开连接
		// defer this.hbTimer.Stop()
	}
	// this.SetInputMsg(true)
	// this.SetRecvMsg(true)
	//NOTE: 数据竞争, calrecv, calsend 可能在SubGo返回时 正在被sendLoop, recvLoop使用; 已修改 SubGo 参数设置CancelFunc了.
	this.thgo.SubGo(this.recvLoop, &this.calrecv)
	this.thgo.SubGo(this.sendLoop, &this.calsend)

}

// Send 发送消息
func (sess *NetSess) Send(msg msgdef.IMsg) {
	if sess.IsClosed() {
		logger.Warnf("[NetSess] id:%d Send after sess close %s %s %s", sess.id, sess.conn.RemoteAddr(), msg.Name(), msg)
		return
	}

	sess.sendBuf.Put(msg)
}

// SendNow 立刻发送消息 只能用在sess加入管理之前
func (sess *NetSess) SendNow(msg msgdef.IMsg) {
	if sess.IsClosed() {
		logger.Warnf("[NetSess] Send after sess close %s %s %s", sess.conn.RemoteAddr(), msg.Name(), msg)
		return
	}
	buf := pool.Get(msg.Size() + MsgHeadSize)
	defer pool.Put(buf)
	msgBuf, err := EncodeMsgWithEncrypt(msg, buf, true, sess._encryEnabled)
	if err != nil {
		logger.Error("[NetSess] sendLoop encode message error ", err)
		return
	}
	_, err = sess.conn.Write(msgBuf)
	if err != nil {
		logger.Error("[NetSess] SendNow message  errno: ", GetErrno(err), " msg: ", err)
		sess.conn.Close()

	}
}

// SendRaw 发送原始消息
func (sess *NetSess) GetConn() net.Conn {
	return sess.conn
}

// SendRaw 发送原始消息
func (sess *NetSess) SendRaw(rawMsg []byte) {
	if sess.IsClosed() {
		logger.Warn("[NetSess] SendRaw after sess close ", sess.conn.RemoteAddr())
		return
	}

	sess.sendBuf.Put(rawMsg)
}

// Touch 心跳后 标记下次超时时间
func (sess *NetSess) Touch() {
	if sess.IsSrvToClientSess() {
		sess.hbTimer.Reset(sess.hbTimerInterval)
	}
}

func (sess *NetSess) verifySess() bool {
	if sess.IsSrvToClientSess() {
		//我是服务端端的客户端会话 ,验证客户端的会话认证消息并返回验证成功,验证失败则关闭连接
		conn := sess.conn
		logger.Infof("[SessMgr] acceptConn ip %s start.", conn.RemoteAddr().String())
		msg, _, _, err := readARQMsgForward(conn, sess.BuffData)
		//如果是连接扫描就强制关掉
		if err != nil || msg == nil {
			logger.Error("accept conn and  read first message error ", err, conn.RemoteAddr())
			sess.Close()
			return false
		}
		var im msgdef.ISessionVerifyReqMsg
		var ok bool
		if im, ok = msg.(msgdef.ISessionVerifyReqMsg); !ok {
			logger.Error("[SessMgr] acceptConn read first message , but message is not client verify req ", conn.RemoteAddr(), "messageName:", msg.Name())
			sess.Close()
			return false
		}
		if err := sess.callback.verifySess(im, sess); err != nil {
			logger.Error("[SessMgr] acceptConn client verify failed", conn.RemoteAddr(), err)
			sess.Close()
			return false
		}
		logger.Infof("[SessMgr] acceptConn ip %s end.", conn.RemoteAddr().String())
		sess.DoNormalMsg("SessVerified", im)
	}
	return true
}

func (sess *NetSess) recvLoop(ctx context.Context) {
	if !sess.verifySess() {
		return
	}
	for {
		select {
		case <-ctx.Done():
			return
		default:
			// sess.BuffData = make([]byte, MaxMsgBuffer)
			msg, msgID, _, err := readARQMsgForward(sess.conn, sess.BuffData)
			if err != nil {
				if sess.IsClosed() {
					return
				}
				if err.Error() == "EOF" {
					logger.Infof("[NetSess,%v] recvLoop sess[%v] disconnect .", sess.IsClientToSrvSess(), sess.conn.RemoteAddr())
				} else if errno := GetErrno(err); errno == 10054 {
					logger.Infof("[NetSess,%v] recvLoop sess[%v] disconnect 10054(%v).", sess.IsClientToSrvSess(), sess.conn.RemoteAddr(), err)
				} else {
					logger.Errorf("[NetSess,%v] recvLoop tcp read message errno: %d err: %v addr: %s; pid: %d", sess.IsClientToSrvSess(),
						errno, err, sess.conn.RemoteAddr(), sess.GetID())
				}
				sess.Close()
				return
			} else if msg != nil {
				if msg.Name() == "HeartBeat" {
					//如果我是服务端会话(非客户端会话)，我就发回去
					if sess.IsSrvToClientSess() {
						sess.Touch()
						sess.Send(msg)
					}
				}
				if sess._isRecvMsg.Load() {
					switch m := msg.(type) {
					case *msgdef.HeartBeat:
					// case *protoMsg.Client2CenterReq:
					// 	args := serializer.UnSerialize(m.MsgData)
					// 	logger.Debugf(logger.LogKey_Msg, "recv msg :%s to linker,msg:%v", m.MsgName, args)
					case *msgdef.RPCMsg:
						args := serializer.UnSerialize(m.Data)
						logger.Debugf(logger.LogKey_Msg, "recv msg :%s srvtype:%d %v", m.MethodName, m.ServerType, args)
					default:
						logger.Debugf(logger.LogKey_Msg, "recv msg :%s ", msg.Name())

					}
				}

				sess.FireMsg(msg.Name(), msg)
			} else if msgID != 0 {
				//消息没有解出来
				logger.Warnf("Unknown message msgID:%d", msgID)
				sess.Close()
				return
			} else {
				//不可能到这里来
				sess.Close()
				return
			}
			// if rawMsg != nil {
			// 	sess.FireMsg("MsgForward", &RawMsg{msgID, rawMsg})
			// }
		}
	}
}

func (this *NetSess) sendLoop(ctx context.Context) {
	defer func() {
		this.Close()
		this.conn.Close()
	}()
	if this._isClientToSrvSess {
		// this.hbTicker = time.NewTicker(this.hbTickerInterval)
		defer this.hbTicker.Stop()
		// this.hbTimer = &time.Timer{}
	} else {
		// this.hbTicker = &time.Ticker{}
		// this.hbTimer = time.NewTimer(this.hbTimerInterval)
		defer this.hbTimer.Stop()
	}
	for {
		select {
		case <-ctx.Done():
			return
		case <-this.hbTimer.C: //心跳超时
			logger.Infof("[NetSess] timeout Addr:%s id:%d type:%v;", this.conn.RemoteAddr(), this.id, this.stype.String())
			this.Close()
		case <-this.hbTicker.C: //客户端定时发送心跳
			this.Send(&msgdef.HeartBeat{})
		case <-this.closeTimer.C: //顶号的定时关闭连接 计时器
			this.Close()
		case <-this.sendBuf.C: //合并发送包
			this.loopsendMsg()
			// this.loopMsg()
		}
	}
}

// 合并消息写入
func (this *NetSess) loopsendMsg() {
	isinputmsg := this._isInputMsg.Load()
	buf := pool.Get(MaxMsgBuffer)
	defer pool.Put(buf)
	st := pool.NewByteSteam(buf)
	defer func() {
		this.sendMsg(st.GetDataBuff())
	}()
	for {
		data, err := this.sendBuf.Pop()
		if err != nil {
			break
		}
		switch m := data.(type) {
		case msgdef.IMsg:
			{

				if m.Name() == "Hangup" {
					_ = this.sendMsg(st.GetDataBuff())
					// 唯一关闭逻辑
					this.calsend()
					this.calrecv()
					// time.Sleep(time.Second * 5)
					// this.conn.Close()
					return
				}
				// 勇哥说，如果消息加完后小余1000字节的话，有效果
				if st.GetLen()+m.Size()+MsgHeadSize > 1000 {
					if err = this.sendMsg(st.GetDataBuff()); err != nil {
						st.ReSet()
						this.calsend()
						this.calrecv()
						return
					}
					st.ReSet()
				}
				// if m.Size()+MsgHeadSize > len(st.GetNilBuff()) {
				// 	logger.Warnf("loopsendMsg buff len warn.%d > %d;msg:%s", m.Size()+MsgHeadSize, len(st.GetNilBuff()), m.Name())
				// }
				nbuf, err := EncodeMsgWithEncrypt(m, st.GetNilBuff(), true, this._encryEnabled)
				if err != nil {
					logger.Warnf("encode err:%s msg:%s", err, m)
					continue
				}
				st.AddLen(len(nbuf))
				if isinputmsg {
					// switch v := m.(type) {
					// case *msgdef.HeartBeat:
					// case *protoMsg.RpcMsg: //转发消息,需要解包打印
					// 	_, rpcmsg, _ := msgdef.GetMsgDef().GetMsgInfo(uint16(v.MsgID))
					// 	rpcmsg.Unmarshal(v.MsgData)
					// 	logger.Debugf(logger.LogKey_Msg, "%d %s %v", len(nbuf), rpcmsg.Name(), rpcmsg)
					// // case *protoMsg.AOIMsg:
					// // 	for _, aoi := range v.UpdateAOIs {
					// // 		for _, prop := range aoi.Prop.Prop.Prop {
					// // 			if prop.Index == 2002 {
					// // 				tmp := new(protoMsg.Vector3)
					// // 				tmp.Unmarshal(prop.GetMsg_Value())
					// // 				logger.Debugf(logger.LogKey_Msg, "%d %v", aoi.Prop.EntityID, tmp)
					// // 				break
					// // 			}
					// // 		}
					// // 	}
					// // 	logger.Debugf(logger.LogKey_Msg, "%d %s %v", len(nbuf), m.Name(), m)
					// default: //非转发消息,直接打印
					// logger.Debugf(logger.LogKey_Msg, "%d %s %v", len(nbuf), m.Name(), m)
					// }
				}
			}
		case []byte:
			{
				if st.GetLen()+len(m) > 1000 {
					if err = this.sendMsg(st.GetDataBuff()); err != nil {
						st.ReSet()
						this.calsend()
						this.calrecv()
						return
					}
					st.ReSet()
				}
				st.Copy(m)
				if isinputmsg {
					tmp := make([]byte, len(m))
					copy(tmp, m)
					_, err := DecodeBytes(tmp)
					if err != nil {
						logger.Warn(err)
					} else {
						// switch v := msg.(type) {
						// case *protoMsg.RpcMsg:
						// 	_, rpcmsg, _ := msgdef.GetMsgDef().GetMsgInfo(uint16(v.MsgID))
						// 	rpcmsg.Unmarshal(v.MsgData)
						// 	logger.Debugf(logger.LogKey_Msg, "%d %s %v", len(tmp), rpcmsg.Name(), rpcmsg)
						// // case *protoMsg.AOIMsg:
						// // 	for _, aoi := range v.UpdateAOIs {
						// // 		for _, prop := range aoi.Prop.Prop.Prop {
						// // 			if prop.Index == 2002 {
						// // 				tmp := new(protoMsg.Vector3)
						// // 				tmp.Unmarshal(prop.GetMsg_Value())
						// // 				logger.Debugf(logger.LogKey_Msg, "%d %v", aoi.Prop.EntityID, tmp)
						// // 				break
						// // 			}
						// // 		}
						// // 	}
						// // 	logger.Debugf(logger.LogKey_Msg, "%d %s %v", len(tmp), msg.Name(), msg)
						// default:
						// 	logger.Debugf(logger.LogKey_Msg, "%d %s %v", len(tmp), msg.Name(), msg)
						// }
					}
				}
			}
		}
	}
}

func (this *NetSess) sendMsg(msgBuf []byte) error {
	if len(msgBuf) == 0 {
		return nil
	}
	_, err := this.conn.Write(msgBuf)
	if err != nil {
		logger.Warnf(" sendMsg errno: %v ", err)
		return err

	}
	return nil
}

// Close 关闭
func (sess *NetSess) Close() {
	if !sess._isClosed.CompareAndSwap(false, true) {
		//表示被运行过
		return
	}

	if sess.callback != nil {
		//	log.Error("[NetSess] Close  connNotifier")
		sess.callback.connErr(sess)
	}
	//连接断开后，给逻辑层发的通知
	if sess.IMsgHandler != nil {
		sess.FireMsg("SessClosed", sess.GetID()) //连接主动或被动关闭，通知逻辑层
	}
	// 发起挂断session，不能使用Send
	sess.sendBuf.Put(&msgdef.Hangup{})
	logger.Infof("Sess Close. pid:%d", sess.GetID())
	// sess.hbTicker.Stop()
}

// RemoteAddr 远程地址
func (sess *NetSess) RemoteAddr() string {
	return sess.conn.RemoteAddr().String()
}

// IsVerified 是否验证的连接
func (sess *NetSess) IsVerified() bool {
	return sess._isVerified
}

// SetVerify 设置已经验证
func (sess *NetSess) SetVerify() {
	sess._isVerified = true
}

// IsClientToSrvSess 本会话 是否是客户端会话
func (sess *NetSess) IsClientToSrvSess() bool {
	return sess._isClientToSrvSess
}
func (sess *NetSess) IsSrvToClientSess() bool {
	return !sess._isClientToSrvSess
}

// SetID 设置ID
func (sess *NetSess) SetID(id uint64) {
	sess.id = id
}

// GetID 获取ID
func (sess *NetSess) GetID() uint64 {
	return sess.id
}

// sess 可能是玩家会话, 也有可能是服务器之间的会话; 服务器之间会有 服务和客户端会话两种; 所以有的时候是要区分的
func (sess *NetSess) IsPlayerClientSess() bool {
	return sess.stype == iserver.ServerTypeClient || sess.stype == 0
}
func (sess *NetSess) GetType() iserver.ServerType2 {
	return sess.stype.Uint8()
}

func (sess *NetSess) SetType(stype iserver.ServerType) {
	sess.stype = stype
}

// 设置是否输出消息
func (sess *NetSess) SetInputMsg(v bool) {
	sess._isInputMsg.Store(v)
}

func (sess *NetSess) SetRecvMsg(v bool) {
	sess._isRecvMsg.Store(v)
}

// IsClosed 返回sess是否已经关闭
func (sess *NetSess) IsClosed() bool {
	return sess._isClosed.Load()
}

// 被人顶了，关链接逻辑
func (sess *NetSess) SetDuplicate() {
	sess.closeTimer.Reset(time.Second * 5)
}

// modify by zgb 2021/7/30
// 下面2個接口是用来当玩家掉线时，上线后，把没有发出去的包再发一遍，但是这里有2个问题，1。顶号时，因为下线的的消息hangup在未发完的消息队列种，会
//刷新给新的sess，导致新连接的玩家会被踢下线； 2.刷新新的数据给新的连接，可能会对客户端造成意外的情况，比如客户端还没接收到该消息依赖的系统，有可能破坏
// 客户端的稳定性，所以这里先注释掉

// FetchBacklog 获取积压消息
func (sess *NetSess) FetchBacklog(o iserver.ISess) {

}

// FlushBacklog 刷新积压消息
func (sess *NetSess) FlushBacklog() {

}
